package com.javaforever.gatescore.gui;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Enumeration;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * @ClassName: ZipCompressor
 * @CreateTime Apr 28, 2013 1:12:16 PM
 * @author : Mayi
 * @Description: 压缩文件的通用工具类-采用org.apache.tools.zip.ZipOutputStream实现，较复杂。
 *
 */
public class ZipCompressor {
    static final int BUFFER = 8192;  
    private File zipFile;  
    
    public ZipCompressor(){
    	super();
    }
    
    /**
     * 压缩文件构造函数
     * @param pathName 压缩的文件存放目录
     */
    public ZipCompressor(String pathName) {  
        zipFile = new File(pathName);  
    }  
  
    /**
     * 执行压缩操作
     * @param srcPathName 被压缩的文件/文件夹
     */
    public void compressExe(String srcPathName) throws Exception{  
        File file = new File(srcPathName);        
        if (!file.exists()){
        	throw new RuntimeException(srcPathName + "不存在！");  
        }
        try (FileOutputStream fileOutputStream = new FileOutputStream(zipFile)){ 
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,new CRC32());  
            ZipOutputStream out = new ZipOutputStream(cos);  
            String basedir = "";  
            compressByType(file, out, basedir);  
        }  
    }  
    
    /**
     * 执行压缩操作忽略templates.zip
     * @param srcPathName 被压缩的文件/文件夹
     */
    public void compressExeIgnoreTemplates(String srcPathName) throws Exception{  
        File file = new File(srcPathName);  
        if (!file.exists()){
        	throw new RuntimeException(srcPathName + "不存在！");  
        }
        try (FileOutputStream fileOutputStream = new FileOutputStream(zipFile)){  
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,new CRC32());  
            try (ZipOutputStream out = new ZipOutputStream(cos);){ 
            	String basedir = "";  
            	compressByTypeIgnoreTemplates(file, out, basedir);  
            }
        } 
    }  
  
    /**
     * 判断是目录还是文件，根据类型（文件/文件夹）执行不同的压缩方法
     * @param file 
     * @param out
     * @param basedir
     */
    private  void compressByType(File file, ZipOutputStream out, String basedir) throws Exception{  
        /* 判断是目录还是文件 */  
        if (file.isDirectory()) {  
            this.compressDirectory(file, out, basedir);  
        } else {  
            this.compressFile(file, out, basedir);  
        }  
    }  
    
    /**
     * 判断是目录还是文件，根据类型（文件/文件夹）执行不同的压缩方法
     * @param file 
     * @param out
     * @param basedir
     */
    private  void compressByTypeIgnoreTemplates(File file, ZipOutputStream out, String basedir) throws Exception {  
        /* 判断是目录还是文件 */  
        if (file.isDirectory()) {  
            this.compressDirectoryIgnoreTemplates(file, out, basedir);  
        } else {  
            this.compressFileIgnoreTemplates(file, out, basedir);  
        }  
    }  
  
    /**
     * 压缩一个目录
     * @param dir
     * @param out
     * @param basedir
     */
    private  void compressDirectory(File dir, ZipOutputStream out, String basedir) throws Exception {  
        if (!dir.exists()){
        	 return;  
        }
           
        File[] files = dir.listFiles();  
        for (int i = 0; i < files.length; i++) {  
            /* 递归 */  
        	compressByType(files[i], out, basedir + dir.getName() + "/");  
        }  
    }  
    
    /**
     * 压缩一个目录
     * @param dir
     * @param out
     * @param basedir
     */
    private  void compressDirectoryIgnoreTemplates(File dir, ZipOutputStream out, String basedir) throws Exception{  
        if (!dir.exists()){
        	 return;  
        }
           
        File[] files = dir.listFiles();  
        for (int i = 0; i < files.length; i++) {  
            /* 递归 */  
        	compressByTypeIgnoreTemplates(files[i], out, basedir + dir.getName() + "/");  
        }  
    }  
    
    /**
     * 压缩一个文件
     * @param file
     * @param out
     * @param basedir
     */
    private  void compressFile(File file, ZipOutputStream out, String basedir) throws Exception{  
        if (!file.exists()) {  
            return;  
        }  
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))){  
            ZipEntry entry = new ZipEntry(basedir + file.getName());  
            out.putNextEntry(entry);  
            int count;  
            byte data[] = new byte[BUFFER];  
            while ((count = bis.read(data, 0, BUFFER)) != -1) {  
                out.write(data, 0, count);  
            }  
        } 
    }  
  
    /**
     * 压缩一个文件
     * @param file
     * @param out
     * @param basedir
     */
    private  void compressFileIgnoreTemplates(File file, ZipOutputStream out, String basedir) throws Exception {  
        if (!file.exists()|| file.getName().equals("templates.zip")) {  
            return;  
        }  
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))){ 
            ZipEntry entry = new ZipEntry(basedir + file.getName());  
            out.putNextEntry(entry);  
            int count;  
            byte data[] = new byte[BUFFER];  
            while ((count = bis.read(data, 0, BUFFER)) != -1) {  
                out.write(data, 0, count);  
            }  
        }
    }  
    
    /**
     * 解压缩一个文件
     * @param file
     * @param out
     * @param basedir
     */
    private  void unCompressFile(File file, ZipOutputStream out, String basedir) throws Exception{  
        if (!file.exists()) {  
            return;  
        }  
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))){ 
            ZipEntry entry = new ZipEntry(basedir + file.getName());  
            out.putNextEntry(entry);  
            int count;  
            byte data[] = new byte[BUFFER];  
            while ((count = bis.read(data, 0, BUFFER)) != -1) {  
                out.write(data, 0, count);  
            }  
        } 
    } 
    
    /** 
     * 压缩文件-由于out要在递归调用外,所以封装一个方法用来 
     * 调用ZipFiles(ZipOutputStream out,String path,File... srcFiles) 
     * @param zip 
     * @param path 
     * @param srcFiles 
     * @throws IOException 
     * @author isea533 
     */  
    public  void ZipFiles(File zip,String path,File... srcFiles) throws Exception{  
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zip))){ 
	        new ZipCompressor().ZipFiles(out,path,srcFiles);  
        }
    }  
    /** 
     * 压缩文件-File 
     * @param zipFile  zip文件 
     * @param srcFiles 被压缩源文件 
     * @author isea533 
     */  
	public  void ZipFiles(ZipOutputStream out, String path, File... srcFiles) throws Exception {
		path = path.replaceAll("\\*", "/");
		if (!path.endsWith("/")) {
			path += "/";
		}
		byte[] buf = new byte[1024];
		for (int i = 0; i < srcFiles.length; i++) {
			if (srcFiles[i].isDirectory()) {
				File[] files = srcFiles[i].listFiles();
				String srcPath = srcFiles[i].getName();
				srcPath = srcPath.replaceAll("\\*", "/");
				if (!srcPath.endsWith("/")) {
					srcPath += "/";
				}
				out.putNextEntry(new ZipEntry(path + srcPath));
				ZipFiles(out, path + srcPath, files);
			} else {
				try (FileInputStream in = new FileInputStream(srcFiles[i])) {
					out.putNextEntry(new ZipEntry(path + srcFiles[i].getName()));
					int len;
					while ((len = in.read(buf)) > 0) {
						out.write(buf, 0, len);
					}
					out.closeEntry();
				}
			}
		}
	}
    
    /** 
     * 解压到指定目录 
     * @param zipPath 
     * @param descDir 
     * @author isea533 
     */  
    public  void unZipFiles(String zipPath,String descDir)throws IOException{  
        unZipFiles(new File(zipPath), descDir);  
    }  

	/**
	 * 解压文件到指定目录
	 * 
	 * @param zipFile
	 * @param descDir
	 * @author isea533
	 */
	@SuppressWarnings("rawtypes")
	public  void unZipFiles(File zipFile, String descDir) throws IOException {
		File pathFile = new File(descDir);
		if (!pathFile.exists()) {
			pathFile.mkdirs();
		}
		ZipFile zip = new ZipFile(zipFile);
		for (Enumeration entries = zip.entries(); entries.hasMoreElements();) {
			ZipEntry entry = (ZipEntry) entries.nextElement();
			String zipEntryName = entry.getName();
			try (InputStream in = zip.getInputStream(entry)) {
				String outPath = (descDir + zipEntryName).replaceAll("\\*", "/");
				;
				// 判断路径是否存在,不存在则创建文件路径
				File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
				if (!file.exists()) {
					file.mkdirs();
				}
				// 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
				if (new File(outPath).isDirectory()) {
					continue;
				}

				try (OutputStream out = new FileOutputStream(outPath)) {
					byte[] buf1 = new byte[1024];
					int len;
					while ((len = in.read(buf1)) > 0) {
						out.write(buf1, 0, len);
					}
				}
			}
		}
	}
    
    /** 
     * 解压到指定目录 并删除zip文件
     * @param zipPath 
     * @param descDir 
     * @author isea533 
     */  
    public  void unZipFilesAndDeleteOrginal(String zipPath,String descDir)throws Exception{  
    	File f = new File(zipPath);
    	unZipFilesAndDeleteOrginal(f, descDir);  
    	//f.deleteOnExit();    
    } 
    
	/**
	 * 解压文件到指定目录 并删除zip文件
	 * 
	 * @param zipFile
	 * @param descDir
	 * @author isea533
	 */
	@SuppressWarnings("rawtypes")
	public  void unZipFilesAndDeleteOrginal(File zipFile, String descDir) throws Exception {
		File pathFile = new File(descDir);
		if (!pathFile.exists()) {
			pathFile.mkdirs();
		}
		try (ZipFile zip = new ZipFile(zipFile)) {
			for (Enumeration entries = zip.entries(); entries.hasMoreElements();) {
				ZipEntry entry = (ZipEntry) entries.nextElement();
				String zipEntryName = entry.getName();
				try (InputStream in = zip.getInputStream(entry)) {
					String outPath = (descDir + zipEntryName).replaceAll("\\*", "/").replaceAll("//", "/");

					// 判断路径是否存在,不存在则创建文件路径
					File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
					if (!file.exists()) {
						file.mkdirs();
					}
					// 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
					if (new File(outPath).isDirectory()) {
						continue;
					}
					
					Files.copy(in, new File(outPath).toPath(), StandardCopyOption.REPLACE_EXISTING);
				}
			}
			if (zipFile.exists()) zipFile.delete();
		}
	}  
    
}

